Published on

浏览器进程线程模型-字节一面

Authors

浏览器进程线程相关

  1. 浏览器进程模型演进

    • 单进程时代(早期浏览器): 所有功能运行在单个进程中 一个标签页崩溃会导致整个浏览器崩溃

    • 多进程架构(现代浏览器):Chrome 为代表的多进程模型 不同功能模块运行在独立进程中 默认每个标签页一个独立进程

  2. 现代浏览器的主要进程:

  • 浏览器主进程(Browser Process) 唯一性:整个浏览器只有一个主进程 主要职责:

    • 管理浏览器界面(地址栏、书签等)
    • 负责其他进程的创建和销毁
    • 网络请求(部分浏览器)
    • 存储管理(Cookie、LocalStorage)
  • 渲染进程(Renderer Process)

    • 多实例:每个标签页通常对应一个渲染进程(可配置)
    • 沙箱隔离:运行在沙箱环境中,限制系统访问
    • 核心功能:
      • HTML/CSS 解析
      • JavaScript 执行(V8 引擎)
      • 页面渲染(合成器线程等)
  • GPU 进程:处理 GPU 加速任务

  • 插件进程(Plugin Process)每个插件单独进程,防止插件崩溃影响浏览器

  • 网络进程(Network Process)每个标签页一个进程,负责网络资源加载

  1. 浏览器中的关键线程
  • 主线程(Main Thread):
    • 执行 JavaScript(V8 引擎)
    • DOM 解析/构建
    • 样式计算
    • 布局计算
  1. 实例
  • 打开一个网页时,创建一个新的渲染进程,管理地址栏显示,处理书签/历史记录,
  • 浏览器网络进程复制 DNS 解析,建立 TCP 连接,处理 HTTP 请求/响应
  • 渲染进程中的渲染主线程负责解析 HTML→ 构建 DOM→ 计算样式 → 布局 → 绘制,合成器线程:分层 → 光栅化 → 合成
  • 如果包含 Web Worker:创建 Worker 线程执行脚本

带 async 和 await 的事件循环输出

await 下面的代码放进微任务队列

async function a1() {
  console.log('a1')
  await a2()
  console.log('a1 end')
}

async function a2() {
  console.log('a2')
}

setTimeout(() => {
  console.log('setTimeout')
}, 0)

console.log('script')
a1()

new Promise((resolve) => {
  console.log('promise1')
  resolve()
}).then(() => {
  console.log('promise2')
})
console.log('script end')

// script
// a1
// a2
// promise1
// script end
// a1 end

Web Worker :浏览器多线程编程方案

Web Worker 是浏览器提供的 JavaScript 多线程解决方案,允许在主线程之外运行脚本,解决复杂计算导致的页面卡顿问题。

一、核心特性

  1. 独立线程运行

    • 与主线程并发执行
    • 不阻塞 UI 渲染和事件响应
  2. 受限访问

    • 无法直接操作 DOM
    • 不能访问window/document对象
    • 通过postMessage与主线程通信
  3. 沙箱环境

    • 独立全局上下文(WorkerGlobalScope)
    • 需单独加载脚本文件

二、Worker 类型对比

类型生命周期共享性典型应用场景
Dedicated Worker随创建页面关闭而终止仅创建页面可访问页面专属计算任务
Shared Worker所有关联页面关闭后终止多页面/iframe 共享跨页面通信、状态共享
Service Worker可独立于页面存在控制多页面PWA、离线缓存、网络代理

三、使用示例

基础用法

// 主线程
const worker = new Worker('worker.js')

worker.postMessage({ command: 'calculate', data: 1000 })

worker.onmessage = (e) => {
  console.log('Result:', e.data)
}

// worker.js
self.onmessage = (e) => {
  if (e.data.command === 'calculate') {
    const result = heavyCalculation(e.data.data)
    self.postMessage(result)
  }
}